const {pgBuildParam} = require("../tool/toolPage");
const sequelize = require('../db/sequelize')
const {QueryTypes} = require("sequelize");

//数据库操作
class BaseService {

    /**
     * 插入
     * @param mode 实体类类 例：Record
     * @param obj 插入的实体 {title:"标题"}
     * @returns {Promise<TModelAttributes>}
     */
    async createBase(mode, obj) {
        //插入数据
        const res = await mode.create(obj);
        return res.dataValues
    }

    /**
     * 分页
     * @param mode 实体类类 例：Record
     * @param page 分页对象 例：{pageNow: 1, size: 10}
     * @param where where 条件 例：{id: {[Op.gt]: 0}}
     * @param attributes 字段属性 例：['id','name'] || { exclude: ['baz'] } https://sequelize.org/docs/v6/core-concepts/model-querying-basics/
     * @returns {Promise<{total: number, size: number, row: [], pageNow: number}>}
     */
    async pageBase(mode, page = {pageNow: 1, size: 10}, where = {}, attributes = null) {
        const {count, rows} = await mode.findAndCountAll({
            attributes: attributes,
            where: where,
            offset: (page.pageNow - 1) * page.size,
            limit: page.size
        })
        return pgBuildParam(page, count, rows)
    }

    /**
     * 查询list数据
     * @returns {Promise<TModelAttributes|null>}
     * @param mode 实体类类 例：Record
     * @param where where 例：{id:1}
     * @param attributes 字段属性 例：['id','name'] || { exclude: ['baz'] } https://sequelize.org/docs/v6/core-concepts/model-querying-basics/
     */
    async listBase(mode, where, attributes = null) {
        const res = await mode.findAll({
            attributes: attributes,
            where: where
        })
        let arr = [];
        if (res) res.map(m => arr.push(m.dataValues));
        return arr;
    }

    /**
     * 查询单条数据
     * @returns {Promise<TModelAttributes|null>}
     * @param mode 实体类类 例：Record
     * @param where where 例：{id:1}
     * @param attributes 字段属性 例：['id','name'] || { exclude: ['baz'] } https://sequelize.org/docs/v6/core-concepts/model-querying-basics/
     */
    async getBase(mode, where, attributes = null) {
        const res = await mode.findOne({
            attributes: attributes,
            where: where
        })
        return res ? res.dataValues : null
    }

    /**
     * 查询主键数据
     * @returns {Promise<TModelAttributes|null>}
     * @param mode 实体类类 例：Record
     * @param pk 主键值
     * @param attributes 字段属性 例：['id','name'] || { exclude: ['baz'] } https://sequelize.org/docs/v6/core-concepts/model-querying-basics/
     */
    async getBasePk(mode, pk, attributes = null) {
        const res = await mode.findByPk(pk);
        return res;
    }

    /**
     * 修改
     * @param mode 实体类类 例：Record
     * @param obj 修改值 例：{id, title}
     * @param where where 例：{id:1}
     * @returns {Promise<boolean>}
     */
    async updateBase(mode, obj, where) {
        const res = await mode.update(obj, {where: where})
        return res[0] > 0
    }

    /**
     * 删除数据
     * @param mode 实体类类 例：Record
     * @param where where 例：{id:1}
     * @param force 物理或逻辑删除 默认true 真删除
     * @returns {Promise<boolean>}
     */
    async delBase(mode, where, force = true) {
        const res = await mode.destroy({where: where, force: force});
        return res > 0;
    }

    /**
     * sql执行 select:用selectSQL update用：updateSQL delete:用delBase 其余再用这个 返回值不确定
     * @param sql sql
     * @param opt 配置 {plain:false,raw:false,type:QueryTypes.SELECT} plain::如果plain为true,则sequelize将仅返回结果集的第一条记录.如果是false,它将返回所有记录.raw::如果你没有查询的模型定义,请将此项设置为true.type::你正在执行的查询类型.查询类型会影响结果在传回之前的格式.
     * @returns {Promise<{result: *, data: *}>}
     */
    async exec(sql, opt) {
        let r = await sequelize.query(sql, opt);
        // console.log(t);
        return r;
    }

    /**
     * sql查询 注意写列别名
     * @param sql sql
     * @returns {Promise<*>} 查询结果
     */
    async selectSQL(sql) {
        const results = await sequelize.query(sql, {plain: false, raw: true, type: QueryTypes.SELECT});
        // console.log(results); //metadata undefined
        return results;
    }

    /**
     * sql更新
     * @param sql sql
     * @returns {Promise<*>} 影响数量
     */
    async updateSQL(sql) {
        const [results, metadata] = await sequelize.query(sql, {type: QueryTypes.UPDATE});
        // console.log(metadata)//results undefined
        return metadata;
    }
}

const base = new BaseService();
/**
 * 新增或更新
 * @param mode
 * @param obj
 * @param key
 * @returns {Promise<*>}
 */
BaseService.prototype.saveBase = async function (mode, obj, key) {
    //插入数据
    let res;
    if (!obj[key]) {
        res = await base.createBase(mode, obj);
    } else {
        let where = {};
        where[key] = obj[key];
        let newObj = {};
        Object.assign(newObj, obj);
        let up = await base.updateBase(mode, newObj, where);
        if (up) {
            res = newObj;
        }
    }
    return res;

}

module.exports = base